package com.aierkeji.b2c.service;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Optional;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;

import com.aierkeji.b2c.constants.Contants;
import com.aierkeji.b2c.dao.jpa.AkjAlipayLifeSnapDao;
import com.aierkeji.b2c.dao.jpa.AkjAlipayOrderDao;
import com.aierkeji.b2c.dao.jpa.AkjOrderRecordDao;
import com.aierkeji.b2c.dao.jpa.AkjOrderStatusLogDao;
import com.aierkeji.b2c.dao.jpa.AkjOrderTempDao;
import com.aierkeji.b2c.dao.jpa.AkjProductDao;
import com.aierkeji.b2c.dao.jpa.AkjSmsRecordDao;
import com.aierkeji.b2c.entity.AkjAlipayOrder;
import com.aierkeji.b2c.entity.AkjOrderRecord;
import com.aierkeji.b2c.entity.AkjOrderStatusLog;
import com.aierkeji.b2c.entity.AkjOrderTemp;
import com.aierkeji.b2c.entity.AkjProduct;
import com.aierkeji.b2c.entity.AkjSmsRecord;
import com.aierkeji.b2c.entity.constant.OrderStatus;
import com.aierkeji.b2c.entity.constant.Source;
import com.aierkeji.b2c.entity.snapshot.AkjAlipayLifeSnap;
import com.aierkeji.b2c.entity.vo.AlipayConfigVo;
import com.aierkeji.b2c.entity.vo.OrderDetailVo;
import com.aierkeji.b2c.entity.vo.OrderListVo;
import com.aierkeji.b2c.entity.vo.ProductVo;
import com.aierkeji.b2c.utils.AppConfig;
import com.aierkeji.b2c.utils.DateTimeUtils;
import com.aierkeji.b2c.utils.ResultMapHelper;
import com.aierkeji.b2c.utils.StringUtils;
import com.aierkeji.b2c.utils.WebUtils;

@Service
public class AkjOrderService {
	private final Logger log = LogManager.getLogger(getClass());

	@Autowired
	AkjProductDao akjProductDao;
	@Autowired
	AlipayService alipayService;

	@Autowired
	AkjAlipayLifeSnapDao akjAlipayLifeSnapDao;
	@Autowired
	AkjOrderRecordDao akjOrderRecordDao;
	@Autowired
	AkjOrderStatusLogDao akjOrderStatusLogDao;
	@Autowired
	AsyncService asyncService;
	@Autowired
	AkjAlipayOrderDao akjAlipayOrderDao;
	@Autowired
	AkjOrderTempDao akjOrderTempDao;
	
	@Autowired
	AkjSmsRecordDao akjSmsRecordDao;

	public Map<String, Object> getPageConfig(String productId, String salesId) {
		if (StringUtils.isEmpty(productId) || StringUtils.isEmpty(salesId)) {
			return ResultMapHelper.nullParamsResult();
		}

		ProductVo productVo = akjProductDao.getProductVo(productId, salesId);

		if (productVo == null) {
			return ResultMapHelper.nullParamsResult();
		}
		return ResultMapHelper.success(productVo);
	}

	public Map<String, Object> getLicensing(String productId, HttpServletRequest request, Map<String, Object> params) {
		// TODO Auto-generated method stub
		AkjProduct akjProduct = akjProductDao.findAkjProductByProductId(productId);
		if (akjProduct == null) {
			return ResultMapHelper.nullParamsResult();
		}
		AlipayConfigVo configVo = AlipayConfigVo.builder(akjProduct.getAkjAlipayLifeSnap());
		Map<String, Object> result = alipayService.fundAuthOrderAppFreeze(configVo, "预授权",
				akjProduct.getPrice().toString());

		if (result == null) {
			log.info("调用支付宝预授权失败!");
			return ResultMapHelper.failure("调用支付宝预授权失败!");
		}
		if (result.containsKey("data")) {
			AkjAlipayOrder data = (AkjAlipayOrder) result.remove("data");
			String auserId = (String) params.get("salesId");
			String client = (String) params.get("username");
			String location = (String) params.get("address");
			String phone = (String) params.get("phone");
			String ctiy = (String) params.get("city");
			AkjOrderTemp akjOrderTemplete = new AkjOrderTemp(auserId, productId, client, ctiy + location, phone,
					data.getId());
			akjOrderTempDao.save(akjOrderTemplete);
			request.getSession().setAttribute("orderId", data.getId());
			log.info("getLicensing orderId:{} session id :{}", data.getId(), request.getSession().getId());
		}
		return ResultMapHelper.success(result);
	}

	@Transactional
	public Map<String, Object> tradePaySuccess(Map<String, Object> params, HttpServletRequest request) {
		// TODO Auto-generated method stub
		String orderId = (String) params.get("orderId");

		String sessionOrderId = (String) request.getSession().getAttribute("orderId");

		String productId = (String) params.get("productId");
		String auserId = (String) params.get("salesId");
		String client = (String) params.get("username");
		String location = (String) params.get("address");
		String phone = (String) params.get("phone");
		String freezeStatus = (String) params.get("freezeStatus");
		String ctiy = (String) params.get("city");
		log.info("session id :{} tradePaySuccess orderId:{} freezeStatus:{}", request.getSession().getId(), orderId,
				freezeStatus);
		if (WebUtils.checkParamsIsNull(orderId, productId, auserId, client, location, phone, freezeStatus)) {
			return ResultMapHelper.nullParamsResult();
		}
		if (!orderId.equals(sessionOrderId)) {
			log.info("session orderId not correct,session orderID:{},orderId:{}", sessionOrderId, orderId);
//			return ResultMapHelper.nullParamsResult();

		}
		if (!"9000".equals(freezeStatus) && !"8000".equals(freezeStatus)) {
			log.info("not correct freezeStatus:{}", freezeStatus);
			return ResultMapHelper.nullParamsResult();
		}
		AkjProduct akjProduct = akjProductDao.findAkjProductByProductId(productId);
		if (akjProduct == null) {
			return ResultMapHelper.nullParamsResult();
		}
		AlipayConfigVo configVo = AlipayConfigVo.builder(akjProduct.getAkjAlipayLifeSnap());
		Map<String, Object> map = null;
		AkjAlipayOrder result = alipayService.fundAuthQuery(configVo, orderId);
		if (result != null && "SUCCESS".equals(result.getFreezeStatus())) {
			Timestamp now = DateTimeUtils.getCurrentTime();
			AkjOrderRecord akjOrderRecord = new AkjOrderRecord();
			akjOrderRecord.setAuserId(auserId);
			akjOrderRecord.setProductId(productId);
			akjOrderRecord.setBorrowTime(now);
			akjOrderRecord.setCreateAt(now);
			akjOrderRecord.setIsFeeDeposit("CREDIT_AUTH".equals(result.getFreezeType()) ? "1" : "0");
			akjOrderRecord.setDeposit(new BigDecimal(result.getAmount()));
			akjOrderRecord.setClient(client);
			akjOrderRecord.setLocation(ctiy + location);
			akjOrderRecord.setPhone(phone);
			akjOrderRecord.setOrderStatus(OrderStatus.PAY);
			akjOrderRecord.setAliPayUserId(result.getBuyerId());
			Long activationTime = akjProduct.getActivationTime();
			Timestamp lastActivationTime = DateTimeUtils.addDay(now, activationTime.intValue());
			akjOrderRecord.setLastActivationTime(lastActivationTime);
			akjOrderRecord.setLifeId(akjProduct.getAkjAlipayLifeSnap().getId());
			akjOrderRecord.setProductName(akjProduct.getName());
			akjOrderRecord.setOrderNo(result.getOutOrderNo());
			akjOrderRecord.setFreezeStatus(freezeStatus);
			this.akjOrderRecordDao.save(akjOrderRecord);
			result.setOrderRecordId(akjOrderRecord.getId());
			AkjOrderStatusLog akjOrderStatusLog = getAkjOrderStatusLog(now, client, akjOrderRecord.getOrderNo(),
					OrderStatus.PAY);
			akjOrderStatusLogDao.save(akjOrderStatusLog);
			map = ResultMapHelper.success();
			asyncService.sendOrderSms(akjOrderRecord, Contants.PAY_ISSUE_MSG, akjProduct.getAkjAlipayLifeSnap());
			akjOrderTempDao.deleteByAkjAlipayOrderId(orderId);
		} else {
			log.info("支付宝订单查询冻结金额失败!  -----:{}", orderId);
			map = ResultMapHelper.failure("支付宝订单查询冻结金额失败!");
		}
		return map;
	}

	private AkjOrderStatusLog getAkjOrderStatusLog(Timestamp createAt, String name, String oderNo,
			OrderStatus orderStatus) {
		AkjOrderStatusLog akjOrderStatusLog = new AkjOrderStatusLog();
		akjOrderStatusLog.setCreateAt(createAt);
		akjOrderStatusLog.setCreateBy(name);
		akjOrderStatusLog.setOrderNo(oderNo);
		akjOrderStatusLog.setStatus(orderStatus);
		akjOrderStatusLog.setSource(Source.B2C);
		return akjOrderStatusLog;
	}

	public Map<String, Object> query(String pId, String id) {
		if (StringUtils.checkAnyNull(id, pId)) {
			return ResultMapHelper.nullParamsResult();
		}
		AkjAlipayLifeSnap akjAlipayLifeSnap = akjAlipayLifeSnapDao.findFirstLifeByAkjMerchantsOrderByIdDesc(pId);
		if (akjAlipayLifeSnap == null) {
			return ResultMapHelper.nullParamsResult();
		}
		AlipayConfigVo alipayConfigVo = AlipayConfigVo.builder(akjAlipayLifeSnap);

		return alipayService.onlyFundAuthQuery(alipayConfigVo, id);
	}

	public Map<String, Object> getOrderList(String userId, String lifeId) {
		// TODO Auto-generated method stub
		log.info("userId:{},lifeId:{}", userId, lifeId);
		if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(lifeId)) {
			return ResultMapHelper.nonLogin();
		}
		Sort sort = new Sort(Direction.DESC, "borrowTime");
		Pageable pageable = PageRequest.of(0, 100, sort);
		Page<OrderListVo> page = akjOrderRecordDao.getOrderList(userId, lifeId, pageable);
		Map<String, Object> map = ResultMapHelper.success(page);
		map.put("orderStatusList", OrderStatus.changeSearchOptionVo());
		return map;
	}

	@Transactional
	public Map<String, Object> cancel(String id, String userId, String lifeId) {
		// TODO Auto-generated method stub

		Optional<AkjAlipayLifeSnap> lifeOptional = akjAlipayLifeSnapDao.findById(lifeId);
		AkjOrderRecord orderRecord = akjOrderRecordDao.findByIdAndAliPayUserIdAndLifeIdAndIsDeleteAndOrderStatus(id,
				userId, lifeId, false, OrderStatus.PAY);

		if (!lifeOptional.isPresent() || orderRecord == null) {
			return ResultMapHelper.nullParamsResult();
		}

		return cancel(orderRecord, lifeOptional, cancel_center, null);

	}

	@Transactional
	private Map<String, Object> cancel(AkjOrderRecord orderRecord, Optional<AkjAlipayLifeSnap> lifeOptional,
			String type, HttpServletRequest request) {
		// 解冻
		Map<String, Object> resultMap = alipayService.fundAuthOrderUnFreeze(AlipayConfigVo.builder(lifeOptional.get()),
				orderRecord.getOrderNo());
		Timestamp now = DateTimeUtils.getCurrentTime();
		if ("success".equals(resultMap.get("code"))) {
			AkjOrderRecord smsOrderRecord = new AkjOrderRecord();
			BeanUtils.copyProperties(orderRecord, smsOrderRecord);
			smsOrderRecord.setRefundPremium(
					"1".equals(orderRecord.getIsFeeDeposit()) ? BigDecimal.ZERO : orderRecord.getDeposit());
			// 解冻成功
			int count = this.akjOrderRecordDao.updateCancle(orderRecord, OrderStatus.CANCEL,
					DateTimeUtils.getCurrentTime(), "客户自主取消订单",
					"1".equals(orderRecord.getIsFeeDeposit()) ? BigDecimal.ZERO : orderRecord.getDeposit());
			if (count <= 0) {
				log.info("updateCancle failure id:{} lifeId:{} userid:{},type:{}", orderRecord.getId(),
						orderRecord.getLifeId(), orderRecord.getAliPayUserId(), type);
				return ResultMapHelper.failure("更新状态失败!");
			} else {
				AkjOrderStatusLog akjOrderStatusLog = getAkjOrderStatusLog(now, "客户", orderRecord.getOrderNo(),
						OrderStatus.CANCEL);
				akjOrderStatusLog.setRemark(cancel_query.equals(type) ? "客户通过查询页面取消订单" : "客户自主取消订单");
				this.akjOrderStatusLogDao.save(akjOrderStatusLog);
				this.asyncService.sendOrderSms(smsOrderRecord, Contants.SENT_BACK_MSG, lifeOptional.get());
				log.info("updateCancle sucess id:{} lifeId:{} userid:{},type:{}", orderRecord.getId(),
						orderRecord.getLifeId(), orderRecord.getAliPayUserId(), type);
				if (cancel_query.equals(type)) {
					clearYZMSession(request);
				}
				return ResultMapHelper.success();
			}
		} else {
			return ResultMapHelper.failure("取消失败!");
		}
	}

	@Transactional
	public Map<String, Object> tradePayCancel(Map<String, Object> params, HttpServletRequest request) {
		// TODO Auto-generated method stub
		String orderId = (String) params.get("orderId");
		String sessionOrderId = (String) request.getSession().getAttribute("orderId");
		String freezeStatus = (String) params.get("freezeStatus");
		String productId = (String) params.get("productId");
		log.info("tradePayCancel orderId:{} freezeStatus:{}", orderId, freezeStatus);
		if (WebUtils.checkParamsIsNull(orderId, freezeStatus, productId)) {
			return ResultMapHelper.nullParamsResult();
		}
		if (!orderId.equals(sessionOrderId)) {
			log.info("session orderId not correct,session orderID:{},orderId:{}", sessionOrderId, orderId);
//			return ResultMapHelper.nullParamsResult();

		}
		if ("9000".equals(freezeStatus) || "8000".equals(freezeStatus)) {
			log.info("not correct freezeStatus:{}", freezeStatus);
			return ResultMapHelper.nullParamsResult();
		}
		int count = akjAlipayOrderDao.delete(orderId);
		akjOrderTempDao.deleteByAkjAlipayOrderId(orderId);
		log.info("tradePayCancel.count:{} ", count);
		return ResultMapHelper.success(count);
	}

	public Map<String, Object> findByOrderNo(Map<String, Object> params) {
		// TODO Auto-generated method stub
		String orderNo = (String) params.get("orderNo");
		String pageNo = (String) params.get("pageNo");
		Integer pageNoInt = StringUtils.isEmpty(pageNo) ? 1 : Integer.parseInt(pageNo);
		Sort sort = new Sort(Direction.DESC, "borrowTime");
		Pageable pageable = PageRequest.of(pageNoInt - 1, 100, sort);
		Page<OrderDetailVo> page = this.akjOrderRecordDao.getOrderList(orderNo, pageable);
		return ResultMapHelper.success(page);
	}

	private String cancel_query = "query";
	private String cancel_center = "center";

	public Map<String, Object> getYZM(String id, HttpServletRequest request, Map<String, Object> map) {
		// TODO Auto-generated method stub
		String yzm = String.valueOf(new Random().nextInt(899999) + 100000);
		String aliPayUserId = (String) map.get("aliPayUserId");
		String lifeId = (String) map.get("lifeId");
		LocalDateTime sessionSendDate = (LocalDateTime) request.getSession().getAttribute("detail-cancel-created");
		String sessionId = (String) request.getSession().getAttribute("detail-cancel-id");
		if (sessionId != null && sessionId.equals(id) && sessionSendDate != null
				&& sessionSendDate.isAfter(LocalDateTime.now().minusMinutes(1))) {
			return ResultMapHelper.failure("信息已发出，请不要重复发送");
		}
		String ipaddress = WebUtils.getIpAddress(request);
		
		int count = akjSmsRecordDao.countByIp(ipaddress, DateTimeUtils.getTodayStart());
		if(count>Integer.parseInt(AppConfig.getProperty("query.ip.max.send","10"))) {
			log.info("ip max send count ip:{},count:{}", ipaddress,count);
			return ResultMapHelper.failure("超过每天最大可发送次数！");
		}
		AkjOrderRecord akjOrderRecord = this.akjOrderRecordDao
				.findByIdAndAliPayUserIdAndLifeIdAndIsDeleteAndOrderStatus(id, aliPayUserId, lifeId, false,
						OrderStatus.PAY);
		if (akjOrderRecord == null) {
			return ResultMapHelper.failure("订单信息有误！");
		}
		Optional<AkjAlipayLifeSnap> lifeOptional = akjAlipayLifeSnapDao.findById(akjOrderRecord.getLifeId());
		if (!lifeOptional.isPresent()) {
			return ResultMapHelper.failure("订单-生活号信息有误！");
		}
		this.asyncService.sendYzm(akjOrderRecord, yzm, lifeOptional.get());
		if(!"unknown".equalsIgnoreCase(ipaddress)&&!ipaddress.contains("127.0.0.1")) {
			AkjSmsRecord akjSmsRecord = new AkjSmsRecord();
			akjSmsRecord.setContent(akjOrderRecord.getOrderNo()+","+yzm);
			akjSmsRecord.setCreatedAt(DateTimeUtils.getCurrentTime());
			akjSmsRecord.setIp(ipaddress);
			akjSmsRecord.setPhone(akjOrderRecord.getPhone());
			akjSmsRecordDao.save(akjSmsRecord);
		}else {
			log.info("ipaddress:{}",ipaddress);
		}
		request.getSession().setAttribute("detail-cancel-yzm", yzm);
		request.getSession().setAttribute("detail-cancel-created", LocalDateTime.now());
		request.getSession().setAttribute("detail-cancel-count", 0);
		request.getSession().setAttribute("detail-cancel-id", id);
		return ResultMapHelper.success();
	}

	@Transactional
	public Map<String, Object> cancel(String id, HttpServletRequest request, Map<String, Object> map) {
		// TODO Auto-generated method stub
		String sessionYzm = (String) request.getSession().getAttribute("detail-cancel-yzm");
		LocalDateTime sessionSendDate = (LocalDateTime) request.getSession().getAttribute("detail-cancel-created");
		Integer count = (Integer) request.getSession().getAttribute("detail-cancel-count");
		String sessionId = (String) request.getSession().getAttribute("detail-cancel-id");
		String inputYzm = (String) map.get("yzm");
		String aliPayUserId = (String) map.get("aliPayUserId");
		String lifeId = (String) map.get("lifeId");
		log.info("session yzm:{},sessionSendDate:{},count:{},sessionId:{},input yzm:{},id:{}", sessionYzm,
				sessionSendDate, count, sessionId, inputYzm, id);
		if (StringUtils.checkAnyNull(inputYzm, aliPayUserId, lifeId)) {
			return ResultMapHelper.nullParamsResult();
		}
		if (sessionSendDate == null || count == null || StringUtils.checkAnyNull(sessionYzm, sessionId)) {
			log.info("-----no sesssion msg----");
			return ResultMapHelper.failure("验证码过期，请重新获取!");
		}
		if (!sessionId.equals(id)) {
			log.info("----session id 和输入的id 不一致----");
			return ResultMapHelper.failure("验证码过期，请重新获取!");
		}
		if (!sessionId.equals(id) || sessionSendDate.isBefore(LocalDateTime.now().minusMinutes(5))) {
			log.info("----验证码过期----");
			clearYZMSession(request);
			return ResultMapHelper.failure("验证码过期，请重新获取!");
		}
		if (sessionYzm.equals(inputYzm)) {
			AkjOrderRecord akjOrderRecord = this.akjOrderRecordDao
					.findByIdAndAliPayUserIdAndLifeIdAndIsDeleteAndOrderStatus(id, aliPayUserId, lifeId, false,
							OrderStatus.PAY);
			if (akjOrderRecord == null) {
				clearYZMSession(request);
				return ResultMapHelper.failure("订单信息有误！");
			}
			Optional<AkjAlipayLifeSnap> lifeOptional = akjAlipayLifeSnapDao.findById(akjOrderRecord.getLifeId());
			if (!lifeOptional.isPresent()) {
				clearYZMSession(request);
				return ResultMapHelper.failure("订单-生活号信息有误！");
			}

			return cancel(akjOrderRecord, lifeOptional, cancel_query, request);

		} else {
			count = count + 1;
			if (count >= 5) {
				clearYZMSession(request);
				return ResultMapHelper.failure("验证码输入超过5次，请重新获取验证码！");
			}
			request.getSession().setAttribute("detail-cancel-count", count);
			return ResultMapHelper.failure("验证码输入错误，请重新输入！");
		}

	}

	private void clearYZMSession(HttpServletRequest request) {
		request.getSession().removeAttribute("detail-cancel-count");
		request.getSession().removeAttribute("detail-cancel-yzm");
		request.getSession().removeAttribute("detail-cancel-created");
		request.getSession().removeAttribute("detail-cancel-id");
	}
}
